package cn.sc.summer.thread.util;

import cn.hutool.core.collection.CollUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 类名：事务处理线程类
 *
 * @author a-xin
 * @date 2024/4/29 13:57
 */
@Slf4j
@Component
public class TransactionalExecutor implements TransactionSynchronization, DisposableBean {

    public static final String BEFORE_COMMIT = "BEFORE_COMMIT";

    public static final String AFTER_COMMIT = "AFTER_COMMIT";

    private static final ThreadLocal<Map<String, Runnable>> RUNNABLE = new ThreadLocal<>();

    @Resource
    private ThreadUtil threadUtil;

    private ThreadPoolExecutor THREAD_POOL;

    @PostConstruct
    public void init() {
        log.info("==> Start initializing the transactional thread pool...");
        THREAD_POOL = threadUtil.THREAD_POOL();
    }

    @PreDestroy
    public void destroy() {
        log.error("Start destroy the transactional thread pool...");
        if (null != THREAD_POOL && !THREAD_POOL.isShutdown()) {
            THREAD_POOL.shutdown();
        }
    }

    /**
     * 事务提交执行，如果当前执行方法存在事务，则会通过{@link TransactionalExecutor}的afterCommit()方法进行执行，执行条件为当前事务正常提交<br/>
     * 如果当前执行方法不存在事务，则直接执行runnable方法<br/>
     * 请注意：此方法为自定义线程池异步执行，执行过程中产生的异常，在子线程中是不能返回主线程的！！！
     *
     * @param runnable the runnable task
     */
    public void beforeRun(@NonNull Runnable runnable) {
        if (!TransactionSynchronizationManager.isSynchronizationActive()) {
            log.warn("There are no transactions for the current method...");
            runnable.run();
            return;
        }
        log.info("There is a transaction for the current method...");
        Map<String, Runnable> runnableMap = RUNNABLE.get();
        if (CollUtil.isEmpty(runnableMap)) {
            runnableMap = new HashMap<>();
            RUNNABLE.set(runnableMap);
            TransactionSynchronizationManager.registerSynchronization(this);
        }
        runnableMap.put(BEFORE_COMMIT, runnable);
    }

    /**
     * 事务提交执行，如果当前执行方法存在事务，则会通过{@link TransactionalExecutor}的afterCommit()方法进行执行，执行条件为当前事务正常提交<br/>
     * 如果当前执行方法不存在事务，则直接执行runnable方法<br/>
     * 请注意：此方法为自定义线程池异步执行，执行过程中产生的异常，在子线程中是不能返回主线程的！！！
     *
     * @param runnable the runnable task
     */
    public void afterRun(@NonNull Runnable runnable) {
        if (!TransactionSynchronizationManager.isSynchronizationActive()) {
            log.warn("There are no transactions for the current method...");
            runnable.run();
            return;
        }
        log.info("There is a transaction for the current method...");
        Map<String, Runnable> runnableMap = RUNNABLE.get();
        if (CollUtil.isEmpty(runnableMap)) {
            runnableMap = new HashMap<>();
            RUNNABLE.set(runnableMap);
            TransactionSynchronizationManager.registerSynchronization(this);
        }
        runnableMap.put(AFTER_COMMIT, runnable);
    }

    @Override
    public void beforeCommit(boolean readOnly) {
        log.debug("The transaction commit is processed... ");
        Map<String, Runnable> runnableMap = RUNNABLE.get();
        THREAD_POOL.execute(runnableMap.get(BEFORE_COMMIT));
    }

    @Override
    public void afterCommit() {
        log.debug("The transaction commit is processed... ");
        Map<String, Runnable> runnableMap = RUNNABLE.get();
        THREAD_POOL.execute(runnableMap.get(AFTER_COMMIT));
    }

    @Override
    public void afterCompletion(int status) {
        log.info("The current transaction has been processed: {} ... ", status);
        RUNNABLE.remove();
    }

}

